/**
 * Copyright (C) 2020 - 2021, Yaronzz(yaronhuang@foxmail.com). All rights reserved.
 * 
 * Licensed under the MIT License (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://opensource.org/licenses/MIT
 * 
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 * 
 * @author: yaronzz
 * @email:  yaronhuang@foxmail.com
 * @github: https://github.com/yaronzz
 * @note:   Support type -->> int、uint、int64、uint64、bool、float、double、string、vector、list、map<string,XX>
 * 
 */
#pragma once
#include <list>
#include <map>
#include <vector>
#include <string>
#include <iostream>

#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"

namespace aigc
{

/******************************************************
 * Register class or struct members
 * eg:
 * struct Test
 * {
 *      string A;
 *      string B;
 *      AIGC_JSON_HELPER(A, B)
 * };         
 ******************************************************/
#define AIGC_JSON_HELPER(...)                                                          \
    bool AIGCJsonToObject(aigc::JsonHelperPrivate &handle,                             \
                          rapidjson::Value &jsonValue,                                 \
                          std::vector<std::string> &names)                             \
    {                                                                                  \
        std::vector<std::string> standardNames = handle.GetMembersNames(#__VA_ARGS__); \
        if (names.size() <= standardNames.size())                                      \
        {                                                                              \
            for (int i = names.size(); i < (int)standardNames.size(); i++)             \
                names.push_back(standardNames[i]);                                     \
        }                                                                              \
        return handle.SetMembers(names, 0, jsonValue, __VA_ARGS__);                    \
    }                                                                                  \
    bool AIGCObjectToJson(aigc::JsonHelperPrivate &handle,                             \
                          rapidjson::Value &jsonValue,                                 \
                          rapidjson::Document::AllocatorType &allocator,               \
                          std::vector<std::string> &names)                             \
    {                                                                                  \
        std::vector<std::string> standardNames = handle.GetMembersNames(#__VA_ARGS__); \
        if (names.size() <= standardNames.size())                                      \
        {                                                                              \
            for (int i = names.size(); i < (int)standardNames.size(); i++)             \
                names.push_back(standardNames[i]);                                     \
        }                                                                              \
        return handle.GetMembers(names, 0, jsonValue, allocator, __VA_ARGS__);         \
    }


/******************************************************
 * Rename members
 * eg:
 * struct Test
 * {
 *      string A;
 *      string B;
 *      AIGC_JSON_HELPER(A, B)
 *      AIGC_JSON_HELPER_RENAME("a", "b")
 * };         
 ******************************************************/
#define AIGC_JSON_HELPER_RENAME(...)                                            \
    std::vector<std::string> AIGCRenameMembers(aigc::JsonHelperPrivate &handle) \
    {                                                                           \
        return handle.GetMembersNames(#__VA_ARGS__);                            \
    }


/******************************************************
 * Register base-class
 * eg:
 * struct Base
 * {
 *      string name;
 *      AIGC_JSON_HELPER(name)
 * };  
 * struct Test : Base
 * {
 *      string A;
 *      string B;
 *      AIGC_JSON_HELPER(A, B)
 *      AIGC_JSON_HELPER_BASE((Base*)this)
 * };         
 ******************************************************/
#define AIGC_JSON_HELPER_BASE(...)                                           \
    bool AIGCBaseJsonToObject(aigc::JsonHelperPrivate &handle,               \
                              rapidjson::Value &jsonValue)                   \
    {                                                                        \
        return handle.SetBase(jsonValue, __VA_ARGS__);                       \
    }                                                                        \
    bool AIGCBaseObjectToJson(aigc::JsonHelperPrivate &handle,               \
                              rapidjson::Value &jsonValue,                   \
                              rapidjson::Document::AllocatorType &allocator) \
    {                                                                        \
        return handle.GetBase(jsonValue, allocator, __VA_ARGS__);            \
    }



    class JsonHelperPrivate
    {
    public:
        /******************************************************
         *
         * enable_if
         *
         ******************************************************/
        template <bool, class TYPE = void>
        struct enable_if
        {
        };

        template <class TYPE>
        struct enable_if<true, TYPE>
        {
            typedef TYPE type;
        };

    public:
        /******************************************************
         * 
         * Check Interface
         *      If class or struct add AIGC_JSON_HELPER\AIGC_JSON_HELPER_RENAME\AIGC_JSON_HELPER_BASE,
         *      it will go to the correct conver function.
         *
         ******************************************************/
        template <typename T>
        struct HasConverFunction
        {
            template <typename TT>
            static char func(decltype(&TT::AIGCJsonToObject));

            template <typename TT>
            static int func(...);

            const static bool has = (sizeof(func<T>(NULL)) == sizeof(char));
        };

        template <typename T>
        struct HasRenameFunction
        {
            template <typename TT>
            static char func(decltype(&TT::AIGCRenameMembers));
            template <typename TT>
            static int func(...);
            const static bool has = (sizeof(func<T>(NULL)) == sizeof(char));
        };

        template <typename T>
        struct HasBaseConverFunction
        {
            template <typename TT>
            static char func(decltype(&TT::AIGCBaseJsonToObject));
            template <typename TT>
            static int func(...);
            const static bool has = (sizeof(func<T>(NULL)) == sizeof(char));
        };

    public:
        /******************************************************
         *
         * Interface of JsonToObject\ObjectToJson
         *
         ******************************************************/
        template <typename T, typename enable_if<HasConverFunction<T>::has, int>::type = 0>
        bool JsonToObject(T &obj, rapidjson::Value &jsonValue)
        {
            if (!BaseConverJsonToObject(obj, jsonValue))
                return false;
            std::vector<std::string> names = LoadRenameArray(obj);
            return obj.AIGCJsonToObject(*this, jsonValue, names);
        }

        template <typename T, typename enable_if<!HasConverFunction<T>::has, int>::type = 0>
        bool JsonToObject(T &obj, rapidjson::Value &jsonValue)
        {
            if (std::is_enum<T>::value)
            {
                int ivalue;
                if (!JsonToObject(ivalue, jsonValue))
                    return false;

                obj = static_cast<T>(ivalue);
                return true;
            }

            m_message = "unsupported this type.";
            return false;
        }

        template <typename T, typename enable_if<HasConverFunction<T>::has, int>::type = 0>
        bool ObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            if (jsonValue.IsNull())
                jsonValue.SetObject();
            if (!BaseConverObjectToJson(obj, jsonValue, allocator))
                return false;
            std::vector<std::string> names = LoadRenameArray(obj);
            return obj.AIGCObjectToJson(*this, jsonValue, allocator, names);
        }

        template <typename T, typename enable_if<!HasConverFunction<T>::has, int>::type = 0>
        bool ObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            if (std::is_enum<T>::value)
            {
                int ivalue = static_cast<int>(obj);
                return ObjectToJson(ivalue, jsonValue, allocator);
            }

            m_message = "unsupported this type.";
            return false;
        }

        /******************************************************
         *
         * Interface of LoadRenameArray
         *
         ******************************************************/
        template <typename T, typename enable_if<HasRenameFunction<T>::has, int>::type = 0>
        std::vector<std::string> LoadRenameArray(T &obj)
        {
            return obj.AIGCRenameMembers(*this);
        }

        template <typename T, typename enable_if<!HasRenameFunction<T>::has, int>::type = 0>
        std::vector<std::string> LoadRenameArray(T &obj)
        {
            return std::vector<std::string>();
        }

        /******************************************************
         *
         * Interface of BaseConverJsonToObject\BaseConverObjectToJson
         *
         ******************************************************/
        template <typename T, typename enable_if<HasBaseConverFunction<T>::has, int>::type = 0>
        bool BaseConverJsonToObject(T &obj, rapidjson::Value &jsonValue)
        {
            return obj.AIGCBaseJsonToObject(*this, jsonValue);
        }

        template <typename T, typename enable_if<!HasBaseConverFunction<T>::has, int>::type = 0>
        bool BaseConverJsonToObject(T &obj, rapidjson::Value &jsonValue)
        {
            return true;
        }

        template <typename T, typename enable_if<HasBaseConverFunction<T>::has, int>::type = 0>
        bool BaseConverObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            return obj.AIGCBaseObjectToJson(*this, jsonValue, allocator);
        }

        template <typename T, typename enable_if<!HasBaseConverFunction<T>::has, int>::type = 0>
        bool BaseConverObjectToJson(T &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            return true;
        }

    public:
        /******************************************************
        *
        * Tool function
        *
        ******************************************************/
        static std::vector<std::string> StringSplit(const std::string &str)
        {
            std::vector<std::string> array;
            std::string::size_type pos1, pos2;
            pos1 = 0;
            pos2 = str.find(',');
            while (std::string::npos != pos2)
            {
                array.push_back(str.substr(pos1, pos2 - pos1));
                pos1 = pos2 + 1;
                pos2 = str.find(',', pos1);
            }
            if (pos1 != str.length())
                array.push_back(str.substr(pos1));

            return array;
        }

        static void StringTrim(std::vector<std::string> &array)
        {
            for (int i = 0; i < (int)array.size(); i++)
            {
                std::string newStr = array[i];
                if (!newStr.empty())
                {
                    newStr.erase(0, newStr.find_first_not_of(" "));
                    newStr.erase(newStr.find_last_not_of(" ") + 1);
                }
                if (!newStr.empty())
                {
                    newStr.erase(0, newStr.find_first_not_of("\""));
                    newStr.erase(newStr.find_last_not_of("\"") + 1);
                }
                array[i] = newStr;
            }
        }

        /**
         * Get json value type
         */
        static std::string GetJsonValueTypeName(rapidjson::Value &jsonValue)
        {
            switch (jsonValue.GetType())
            {
            case rapidjson::Type::kArrayType:
                return "array";
            case rapidjson::Type::kFalseType:
            case rapidjson::Type::kTrueType:
                return "bool";
            case rapidjson::Type::kObjectType:
                return "object";
            case rapidjson::Type::kStringType:
                return "string";
            case rapidjson::Type::kNumberType:
                return "number";
            default:
                return "string";
            }
        }

        static std::string GetStringFromJsonValue(rapidjson::Value &jsonValue)
        {
            rapidjson::StringBuffer buffer;
            rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);

            jsonValue.Accept(writer);
            std::string ret = std::string(buffer.GetString());
            return ret;
        }

    public:
        /******************************************************
        *
        * Set class/struct members value
        *
        ******************************************************/
        std::vector<std::string> GetMembersNames(const std::string membersStr)
        {
            std::vector<std::string> array = StringSplit(membersStr);
            StringTrim(array);
            return array;
        }

        template <typename TYPE, typename... TYPES>
        bool SetMembers(const std::vector<std::string> &names, int index, rapidjson::Value &jsonValue, TYPE &arg, TYPES &...args)
        {
            if (!SetMembers(names, index, jsonValue, arg))
                return false;

            return SetMembers(names, ++index, jsonValue, args...);
        }

        template <typename TYPE>
        bool SetMembers(const std::vector<std::string> &names, int index, rapidjson::Value &jsonValue, TYPE &arg)
        {
            if (jsonValue.IsNull())
                return true;

            const char *key = names[index].c_str();
            if (!jsonValue.IsObject())
                return false;
            if (!jsonValue.HasMember(key))
                return true;

            if (!JsonToObject(arg, jsonValue[key]))
            {
                m_message = "[" + names[index] + "] " + m_message;
                return false;
            }
            return true;
        }

        /******************************************************
        *
        * Get class/struct members value
        *
        ******************************************************/
        template <typename TYPE, typename... TYPES>
        bool GetMembers(const std::vector<std::string> &names, int index, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE &arg, TYPES &...args)
        {
            if (!GetMembers(names, index, jsonValue, allocator, arg))
                return false;
            return GetMembers(names, ++index, jsonValue, allocator, args...);
        }

        template <typename TYPE>
        bool GetMembers(const std::vector<std::string> &names, int index, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE &arg)
        {
            rapidjson::Value item;
            bool check = ObjectToJson(arg, item, allocator);
            if (!check)
            {
                m_message = "[" + names[index] + "] " + m_message;
                return false;
            }

            if (jsonValue.HasMember(names[index].c_str()))
            {
                jsonValue.RemoveMember(names[index].c_str());
            }

            rapidjson::Value key;
            key.SetString(names[index].c_str(), names[index].length(), allocator);
            jsonValue.AddMember(key, item, allocator);
            return true;
        }

    public:
        /******************************************************
        *
        * Set base class value
        *
        ******************************************************/
        template <typename TYPE, typename... TYPES>
        bool SetBase(rapidjson::Value &jsonValue, TYPE *arg, TYPES *...args)
        {
            if (!SetBase(jsonValue, arg))
                return false;
            return SetBase(jsonValue, args...);
        }

        template <typename TYPE>
        bool SetBase(rapidjson::Value &jsonValue, TYPE *arg)
        {
            return JsonToObject(*arg, jsonValue);
        }

        /******************************************************
        *
        * Get base class value
        *
        ******************************************************/
        template <typename TYPE, typename... TYPES>
        bool GetBase(rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE *arg, TYPES *...args)
        {
            if (!GetBase(jsonValue, allocator, arg))
                return false;
            return GetBase(jsonValue, allocator, args...);
        }

        template <typename TYPE>
        bool GetBase(rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator, TYPE *arg)
        {
            return ObjectToJson(*arg, jsonValue, allocator);
        }

    public:
        /******************************************************
         * Conver base-type : Json string to base-type
         * Contain: int\uint、int64_t\uint64_t、bool、float
         *          double、string、vector、list、map<string,XX>
         *
         ******************************************************/
        bool JsonToObject(int &obj, rapidjson::Value &jsonValue)
        {
            if (!jsonValue.IsInt())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is int.";
                return false;
            }
            obj = jsonValue.GetInt();
            return true;
        }

        bool JsonToObject(unsigned int &obj, rapidjson::Value &jsonValue)
        {
            if (!jsonValue.IsUint())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is unsigned int.";
                return false;
            }
            obj = jsonValue.GetUint();
            return true;
        }

        bool JsonToObject(int64_t &obj, rapidjson::Value &jsonValue)
        {
            if (!jsonValue.IsInt64())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is int64_t.";
                return false;
            }
            obj = jsonValue.GetInt64();
            return true;
        }

        bool JsonToObject(uint64_t &obj, rapidjson::Value &jsonValue)
        {
            if (!jsonValue.IsUint64())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is uint64_t.";
                return false;
            }
            obj = jsonValue.GetUint64();
            return true;
        }

        bool JsonToObject(bool &obj, rapidjson::Value &jsonValue)
        {
            if (!jsonValue.IsBool())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is bool.";
                return false;
            }
            obj = jsonValue.GetBool();
            return true;
        }

        bool JsonToObject(float &obj, rapidjson::Value &jsonValue)
        {
            if (!jsonValue.IsNumber())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is float.";
                return false;
            }
            obj = jsonValue.GetFloat();
            return true;
        }

        bool JsonToObject(double &obj, rapidjson::Value &jsonValue)
        {
            if (!jsonValue.IsNumber())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is double.";
                return false;
            }
            obj = jsonValue.GetDouble();
            return true;
        }

        bool JsonToObject(std::string &obj, rapidjson::Value &jsonValue)
        {
            obj = "";
            if (jsonValue.IsNull())
                return true;
            //object or number conver to string
            else if (jsonValue.IsObject() || jsonValue.IsNumber())
                obj = GetStringFromJsonValue(jsonValue);
            else if (!jsonValue.IsString())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is string.";
                return false;
            }
            else
                obj = jsonValue.GetString();

            return true;
        }

        template <typename TYPE>
        bool JsonToObject(std::vector<TYPE> &obj, rapidjson::Value &jsonValue)
        {
            obj.clear();
            if (!jsonValue.IsArray())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is std::vector<TYPE>.";
                return false;
            }

            auto array = jsonValue.GetArray();
            for (unsigned int i = 0; i < array.Size(); i++)
            {
                TYPE item;
                if (!JsonToObject(item, array[i]))
                    return false;
                obj.push_back(item);
            }
            return true;
        }

        template <typename TYPE>
        bool JsonToObject(std::list<TYPE> &obj, rapidjson::Value &jsonValue)
        {
            obj.clear();
            if (!jsonValue.IsArray())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is std::list<TYPE>.";
                return false;
            }

            auto array = jsonValue.GetArray();
            for (unsigned int i = 0; i < array.Size(); i++)
            {
                TYPE item;
                if (!JsonToObject(item, array[i]))
                    return false;
                obj.push_back(item);
            }
            return true;
        }

        template <typename TYPE>
        bool JsonToObject(std::map<std::string, TYPE> &obj, rapidjson::Value &jsonValue)
        {
            obj.clear();
            if (!jsonValue.IsObject())
            {
                m_message = "json-value is " + GetJsonValueTypeName(jsonValue) + " but object is std::map<std::string, TYPE>.";
                return false;
            }

            for (auto iter = jsonValue.MemberBegin(); iter != jsonValue.MemberEnd(); ++iter)
            {
                auto key = (iter->name).GetString();
                auto &value = jsonValue[key];

                TYPE item;
                if (!JsonToObject(item, value))
                    return false;

                obj.insert(std::pair<std::string, TYPE>(key, item));
            }
            return true;
        }

    public:
        /******************************************************
         * Conver base-type : base-type to json string
         * Contain: int\uint、int64_t\uint64_t、bool、float
         *          double、string、vector、list、map<string,XX>
         *
         ******************************************************/
        bool ObjectToJson(int &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetInt(obj);
            return true;
        }

        bool ObjectToJson(unsigned int &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetUint(obj);
            return true;
        }

        bool ObjectToJson(int64_t &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetInt64(obj);
            return true;
        }

        bool ObjectToJson(uint64_t &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetUint64(obj);
            return true;
        }

        bool ObjectToJson(bool &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetBool(obj);
            return true;
        }

        bool ObjectToJson(float &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetFloat(obj);
            return true;
        }

        bool ObjectToJson(double &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetDouble(obj);
            return true;
        }

        bool ObjectToJson(std::string &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetString(obj.c_str(), obj.length(), allocator);
            return true;
        }
       
        template <typename TYPE>
        bool ObjectToJson(std::vector<TYPE> &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            rapidjson::Value array(rapidjson::Type::kArrayType);
            for (unsigned int i = 0; i < obj.size(); i++)
            {
                rapidjson::Value item;
                if (!ObjectToJson(obj[i], item, allocator))
                    return false;

                array.PushBack(item, allocator);
            }

            jsonValue = array;
            return true;
        }

        template <typename TYPE>
        bool ObjectToJson(std::list<TYPE> &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            rapidjson::Value array(rapidjson::Type::kArrayType);
            for (auto i = obj.begin(); i != obj.end(); i++)
            {
                rapidjson::Value item;
                if (!ObjectToJson(*i, item, allocator))
                    return false;

                array.PushBack(item, allocator);
            }

            jsonValue = array;
            return true;
        }

        template <typename TYPE>
        bool ObjectToJson(std::map<std::string, TYPE> &obj, rapidjson::Value &jsonValue, rapidjson::Document::AllocatorType &allocator)
        {
            jsonValue.SetObject();
            for (auto iter = obj.begin(); iter != obj.end(); ++iter)
            {
                auto key = iter->first;
                TYPE value = iter->second;

                rapidjson::Value jsonitem;
                if (!ObjectToJson(value, jsonitem, allocator))
                    return false;

                rapidjson::Value jsonkey;
                jsonkey.SetString(key.c_str(), key.length(), allocator);

                jsonValue.AddMember(jsonkey, jsonitem, allocator);
            }
            return true;
        }

    public:
        std::string m_message;
    };

    class JsonHelper
    {
    public:
        /**
         * @brief conver json string to class | struct
         * @param obj : class or struct
         * @param jsonStr : json string 
         * @param keys : the path of the object
         * @param message : printf err message when conver failed
         */
        template <typename T>
        static bool JsonToObject(T &obj, const std::string &jsonStr, const std::vector<std::string> keys = {}, std::string *message = NULL)
        {
            //Parse json string
            rapidjson::Document root;
            root.Parse(jsonStr.c_str());
            if (root.IsNull())
            {
                if (message)
                    *message = "Json string can't parse.";
                return false;
            }

            //Go to the key-path
            std::string path;
            rapidjson::Value &value = root;
            for (int i = 0; i < (int)keys.size(); i++)
            {
                const char *find = keys[i].c_str();
                if (!path.empty())
                    path += "->";
                path += keys[i];

                if (!value.IsObject() || !value.HasMember(find))
                {
                    if (message)
                        *message = "Can't parse the path [" + path + "].";
                    return false;
                }
                value = value[find];
            }

            //Conver
            JsonHelperPrivate handle;
            if (!handle.JsonToObject(obj, value))
            {
                if (message)
                    *message = handle.m_message;
                return false;
            }
            return true;
        }

        /**
         * @brief conver json string to class | struct
         * @param jsonStr : json string
         * @param defaultT : default value
         * @param keys : the path of the object
         * @param message : printf err message when conver failed
         */
        template <typename T>
        static T Get(const std::string &jsonStr, T defaultT, const std::vector<std::string> keys = {}, std::string *message = NULL)
        {
            T obj;
            if (JsonToObject(obj, jsonStr, keys, message))
                return obj;

            return defaultT;
        }

        /**
         * @brief conver class | struct to json string 
         * @param errMessage : printf err message when conver failed
         * @param obj : class or struct
         * @param jsonStr : json string 
         */
        template <typename T>
        static bool ObjectToJson(T &obj, std::string &jsonStr, std::string *message = NULL)
        {
            rapidjson::Document root;
            root.SetObject();
            rapidjson::Document::AllocatorType &allocator = root.GetAllocator();

            //Conver
            JsonHelperPrivate handle;
            if (!handle.ObjectToJson(obj, root, allocator))
            {
                if (message)
                    *message = handle.m_message;
                return false;
            }

            jsonStr = handle.GetStringFromJsonValue(root);
            return true;
        }
    };

} // namespace aigc
